package cn.wolfcode.p2p.business.service.impl;

import cn.wolfcode.p2p.Exception.ErrorCode;
import cn.wolfcode.p2p.base.domain.Account;
import cn.wolfcode.p2p.base.domain.AuditBaseDomain;
import cn.wolfcode.p2p.base.domain.LoginInfo;
import cn.wolfcode.p2p.base.domain.UserInfo;
import cn.wolfcode.p2p.base.query.BidRequestQueryObject;
import cn.wolfcode.p2p.base.query.QueryObject;
import cn.wolfcode.p2p.base.service.IAccountService;
import cn.wolfcode.p2p.base.service.ILoginInfoService;
import cn.wolfcode.p2p.base.service.IUserInfoService;
import cn.wolfcode.p2p.business.domain.*;
import cn.wolfcode.p2p.business.mapper.BidRequestMapper;
import cn.wolfcode.p2p.business.service.*;
import cn.wolfcode.p2p.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;

@Service
@Slf4j
public class BidRequestServiceImpl implements IBidRequestService, ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private BidRequestMapper bidRequestMapper;

    @Autowired
    private IAccountService accountService;

    @Autowired
    private IUserInfoService userInfoService;

    @Autowired
    private IBidRequestAuditHistoryService bidRequestAuditHistoryService;

    @Autowired
    private IBidService bidService;

    @Autowired
    private IAccountFlowService accountFlowService;

    @Autowired
    private IPaymentScheduleService paymentScheduleService;

    @Autowired
    private ISystemAccountService systemAccountService;

    @Autowired
    private ISystemAccountFlowService systemAccountFlowService;

    @Autowired
    private IPaymentScheduleDetailService paymentScheduleDetailService;

    @Autowired
    private ICreditTransferService creditTransferService;

    @Autowired
    private IExpAccountService expAccountService;

    @Autowired
    private IExpAccountFlowService expAccountFlowService;

    @Autowired
    private IExpAccountGrantRecordService expAccountGrantRecordService;

    @Autowired
    private ILoginInfoService loginInfoService;


    //1.定义一个ConcurrentLinkedQueue用来保存冲数据库中查到的所有待发标的bidRequest对象
    @Autowired
    private static ConcurrentLinkedDeque<BidRequest> bidRequests = new ConcurrentLinkedDeque<>();

    @Override
    public void apply(BidRequest bidRequest) {
        LoginInfo applier = UserContext.getLoginInfo();
        Account account = accountService.getAccount(applier.getId());
        UserInfo userInfo = userInfoService.getUserInfo(applier.getId());
        //检验参数
        checkParam(bidRequest, account, userInfo);
        BidRequest temp = new BidRequest();
        //设置参数
        insert(bidRequest, applier, temp);
        //更新数据,增加处在借款流程的位状态
        userInfo.addBitState(BitStatesUtils.HAS_BIDREQUEST_IN_PROCESS);
        userInfoService.update(userInfo);
    }

    @Override
    public PageResult queryForPage(QueryObject qo) {
        int count = bidRequestMapper.queryForCount(qo);
        if (count == 0) {
            return PageResult.empty(qo.getPageSize());
        }
        int totalPage = count % qo.getPageSize() == 0 ? count / qo.getPageSize() : count / qo.getPageSize() + 1;
        if (totalPage < qo.getCurrentPage()) {
            qo.setCurrentPage(totalPage);
        }
        List<BidRequest> listData = bidRequestMapper.queryForList(qo);
        return new PageResult(listData, count, qo.getCurrentPage(), qo.getPageSize());

    }

    /**
     * @param id          借款对象的id
     * @param remark      风控备注
     * @param state       审核的结果
     * @param publishTime 发标时间
     */
    @Override
    public void publishBeforeAudit(Long id, String remark, Integer state, Date publishTime) {

        //判断用户是否处在借款待审核的状态
        //获取借款对象
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(id);
        UserInfo userInfo = userInfoService.getUserInfo(bidRequest.getCreateUser().getId());
        AssertUtil.instance().isFalse(bidRequest.getBidRequestState() != Constant.BIDREQUEST_STATE_PUBLISH_STATE_APPLY, ErrorCode.HAVE_TO_REVIEW);

        //设置审核信息
        bidRequestAuditHistoryService.save(bidRequest, state, remark, Constant.APPLY_AUDIT);

        //审核成功
        if (state == AuditBaseDomain.AUTH_SUCCESS) {
            if (publishTime == null) {
                //立即发标
                //将借款的状态设置为招标中
                bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_BIDDING);
                //设置借款的发标日期为new Date
                bidRequest.setPublishTime(new Date());
                //设置风控信息
            } else {
                //设定招标日期
                //将借款的状态设置为待发标
                bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PUBLISH_PENDING);
                //设置借款的发标信息为指定日期
                bidRequest.setPublishTime(publishTime);
            }
            //计算出招标审核的截止日期
            bidRequest.setDisableDate(DateUtils.addDays(bidRequest.getPublishTime(), bidRequest.getDisableDays()));
        } else {
            //审核失败
            //将借款的状态设置为发标审核拒绝
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PUBLISH_REFUSE);
            //去掉用户的处在借款流程的位状态
            userInfo.removeBitState(BitStatesUtils.HAS_BIDREQUEST_IN_PROCESS);
            userInfoService.update(userInfo);
        }
        //设置风控信息
        bidRequest.setNote(remark);
        update(bidRequest);
        //3.当审核为待发标的时候,保存至ConcurrentLinkedQueue
        if ((state == AuditBaseDomain.AUTH_SUCCESS) && (publishTime != null)) {
            log.debug("审核成功,保存待发标");
            bidRequest.setVersion(bidRequest.getVersion() + 1);
            bidRequests.offer(bidRequest);
        }
    }

    @Override
    public void update(BidRequest bidRequest) {
        AssertUtil.instance().isFalse(bidRequestMapper.updateByPrimaryKey(bidRequest) == 0, ErrorCode.INFORMATION_MODIFICATION_ERROR);
    }

    @Override
    public List<BidRequest> queryByStateAndPublishTime() {
        BidRequestQueryObject qo = new BidRequestQueryObject();
        qo.setBidRequestState(Constant.BIDREQUEST_STATE_PUBLISH_PENDING);
        qo.setPageSize(Constant.ANNOUNCEMENT_PAGE_SIZE);
        qo.setOrderBy(Order.ORDERBY_COLUMN_BID_REQUEST_STATE.orderBy);
        qo.setOrderByType(OrderType.ASC.name());
        int[] bidRequestTypes = {Constant.BIDREQUEST_TYPE_NORMAL, Constant.EXPERIENCE_BIDREQUEST_TYPE_CREDITTRANSFER};
        qo.setBidRequestTypes(bidRequestTypes);
        List<BidRequest> bidRequests = bidRequestMapper.queryForList(qo);
        return bidRequests;
    }


    private void insert(BidRequest bidRequest, LoginInfo applier, BidRequest temp) {
        temp.setReturnType(bidRequest.getReturnType());
        temp.setBidRequestState(Constant.BIDREQUEST_STATE_PUBLISH_STATE_APPLY);
        temp.setBidRequestAmount(bidRequest.getBidRequestAmount());
        temp.setCurrentRate(bidRequest.getCurrentRate());
        temp.setMonthes2Return(bidRequest.getMonthes2Return());
        temp.setTotalRewardAmount(CalculatetUtil.calTotalInterest(bidRequest.getReturnType(),
                bidRequest.getBidRequestAmount(), bidRequest.getCurrentRate(), bidRequest.getMonthes2Return()));
        temp.setTitle(bidRequest.getTitle());
        temp.setDescription(bidRequest.getDescription());
        temp.setCreateUser(applier);
        temp.setDisableDays(bidRequest.getDisableDays());
        temp.setMinBidAmount(bidRequest.getMinBidAmount());
        temp.setApplyTime(new Date());
        bidRequestMapper.insert(temp);
    }

    private void checkParam(BidRequest bidRequest, Account account, UserInfo userInfo) {
        //检验参数
        //借款金额是否大于等于系统最低借款,小于等于剩余授信额度
        AssertUtil.instance()
                .isFalse(bidRequest.getBidRequestAmount().compareTo(Constant.SMALLEST_BIDREQUEST_AMOUNT) < 0, ErrorCode.LESS_THAN_THE_MINIMUM_LOAN);
        AssertUtil.instance()
                .isFalse(bidRequest.getBidRequestAmount().compareTo(account.getRemainBorrowLimit()) > 0, ErrorCode.GREATER_THAN_THE_HIGHEST_LOAN);
        //借款利率是否大于等于系统最低利率,小于等于系统最高利率
        AssertUtil.instance()
                .isFalse(bidRequest.getCurrentRate().compareTo(Constant.SMALLEST_CURRENT_RATE) < 0, ErrorCode.LESS_THAN_THE_SYSTEM_MINIMUM_INTEREST_RATE);
        AssertUtil.instance()
                .isFalse(bidRequest.getCurrentRate().compareTo(Constant.MAX_CURRENT_RATE) > 0, ErrorCode.GREATER_THAN_THE_SYSTEM_MINIMUM_INTEREST_RATE);
        //还款的期限
        AssertUtil.instance()
                .isFalse(bidRequest.getMonthes2Return().compareTo(Constant.MINIMUM_REPAYMENT_MONTH) < 0, ErrorCode.LESS_THAN_THE_SYSTEM_MINIMUM_REPAYMENT_MONTH);
        AssertUtil.instance()
                .isFalse(bidRequest.getMonthes2Return().compareTo(Constant.MAXIMUM_REPAYMENT_MONTH) > 0, ErrorCode.GREATER_THAN_THE_SYSTEM_MINIMUM_REPAYMENT_MONTH);
        //是否为系统还款类型
        AssertUtil.instance()
                .isFalse((bidRequest.getReturnType() != Constant.RETURN_TYPE_MONTH_INTEREST_PRINCIPAL) && (bidRequest.getReturnType() != Constant.RETURN_TYPE_MONTH_INTEREST), ErrorCode.REPAYMENT_TYPE_ERROR);
        //是否大于最小投标金额
        AssertUtil.instance()
                .isFalse(bidRequest.getMinBidAmount().compareTo(Constant.SMALLEST_BID_AMOUNT) < 0, ErrorCode.LESS_THAN_THE_MINIMUM_BID_AMOUNT_OF_THE_SYSTEM);
        //是否在系统规定的招标天数
        AssertUtil.instance()
                .isFalse(bidRequest.getDisableDays() < Constant.MINIMUM_TENDER_DAYS, ErrorCode.LESS_THAN_THE_MAXIMUM_NUMBER_OF_BIDDING_DAYS);
        AssertUtil.instance()
                .isFalse(bidRequest.getDisableDays() > Constant.MAXIMUM_NUMBER_OF_BIDDING_DAYS, ErrorCode.GREATER_THAN_THE_MAXIMUM_NUMBER_OF_BIDDING_DAYS);
        //判断借款标题
        AssertUtil.instance().isNotNull(bidRequest.getTitle(), ErrorCode.BORROWING_TITLE_IS_EMPTY)
                //判断借款描述
                .isNotNull(bidRequest.getDescription(), ErrorCode.BORROWING_DESCRIPTION_IS_EMPTY)
                //是否满足借款条件
                .isFalse(!userInfo.hasThree(), ErrorCode.UNMET_BORROWING_CONDITIONS)
                //判断状态:是否处在借款的流程中
                .isFalse(userInfo.hasLoan(), ErrorCode.ALREADY_BORROWED);
    }

    /**
     * 定时发标
     */
    @Override
    public void publishForBidding() {
        /*
            3.判断系统时间是否大于发标时间
            4.将借款对象的状态设置为招标中
            5.从队列中删除该对象
     */
        Date date = new Date();
        Iterator<BidRequest> iterator = bidRequests.iterator();
        while (iterator.hasNext()) {
            BidRequest bidRequest = iterator.next();
            if (bidRequest.getPublishTime().before(date)) {
                log.debug("满足条件,执行发标");
                bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_BIDDING);
                update(bidRequest);
                iterator.remove();
            }
        }

    }

    @Override
    public void listBidRequests() {
        //1.每个一小时查询一次数据库定时器
        log.debug("每小时查询待发标");
        BidRequestQueryObject qo = new BidRequestQueryObject();
        qo.setBidRequestState(Constant.RETURN_TYPE_MONTH_INTEREST_PRINCIPAL);
        qo.setPageSize(Constant.PAGESIZE);
        List<BidRequest> list = bidRequestMapper.queryForList(qo);
        for (BidRequest bidRequest : list) {
            if (!bidRequests.contains(bidRequest)) {
                bidRequests.offer(bidRequest);
            }
        }
    }

    @Override
    public List<BidRequest> queryBiddingByState() {
        BidRequestQueryObject qo = new BidRequestQueryObject();
        qo.setBidRequestState(Constant.BIDREQUEST_STATE_BIDDING);
        qo.setPageSize(Constant.ANNOUNCEMENT_PAGE_SIZE);
        qo.setOrderBy(Order.ORDERBY_COLUMN_PUBLISH_TIME.orderBy);
        qo.setOrderByType(OrderType.ASC.name());
        List<BidRequest> bidRequests = bidRequestMapper.queryForList(qo);
        return bidRequests;
    }

    @Override
    public List<BidRequest> queryExpBiddingByState() {
        BidRequestQueryObject qo = new BidRequestQueryObject();
        qo.setBidRequestState(Constant.BIDREQUEST_STATE_BIDDING);
        qo.setPageSize(Constant.ANNOUNCEMENT_PAGE_SIZE);
        qo.setOrderBy(Order.ORDERBY_COLUMN_PUBLISH_TIME.orderBy);
        qo.setOrderByType(OrderType.ASC.name());
        qo.setBidRequestType(Constant.EXPERIENCE_BIDREQUEST_TYPE_CREDITTRANSFER);
        List<BidRequest> bidRequests = bidRequestMapper.queryForList(qo);
        return bidRequests;
    }

    @Override
    public PageResult investList(BidRequestQueryObject qo) {
        return queryForPage(qo);
    }

    @Override
    public BidRequest getBidRequestById(Long id) {
        return bidRequestMapper.selectByPrimaryKey(id);
    }

    @Override
    public void bidding(Long bidRequestId, BigDecimal amount) {
        AssertUtil.instance().isNotNull(amount, ErrorCode.THE_INVESTMENT_AMOUNT_CANNOT_BE_EMPTY);
        //判断投资金额
        //投资金额是否小于等于可用余额
        LoginInfo loginInfo = UserContext.getLoginInfo();
        Account account = accountService.getAccount(loginInfo.getId());
        BidRequest bidRequest = bidingCheck(bidRequestId, amount, loginInfo, account);
        //判断用户是否为借款人
        AssertUtil.instance().isFalse(bidRequest.getCreateUser().getId().longValue() == loginInfo.getId().longValue(), ErrorCode.CAN_NOT_INVEST_IN_OWN_LOANS);
        //设置借款对象
        //投标数增加
        bidRequest.addBidCount();
        //当前投资总额要增加
        bidRequest.addCurrentSum(amount);
        //设置投标对象
        //投标金额
        bidService.save(bidRequest, amount);
        //设置账户
        //投资人的可用余额要减少,冻结资金要增加
        account.subtractUsableAmount(amount);
        account.addFreezedAmount(amount);
        accountService.update(account);
        //设置流水
        //增加一条流水记录
        accountFlowService.createFreezedSuccessFlow(bidRequest.getTitle(), account, amount);
        //如果是最后一笔投标,则自动进入满标一审
        if (bidRequest.getCurrentSum().compareTo(bidRequest.getBidRequestAmount()) == 0) {
            //将借款对象的状态设置为满标一审
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_APPROVE_PENDING_1);
            //投标对象的状态也随之改变,变为满标一审
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_APPROVE_PENDING_1);
        }
        update(bidRequest);
    }

    @Override
    public void expBidding(Long bidRequestId, BigDecimal amount) {
        AssertUtil.instance().isNotNull(amount, ErrorCode.THE_INVESTMENT_AMOUNT_CANNOT_BE_EMPTY);
        LoginInfo loginInfo = UserContext.getLoginInfo();
        ExpAccount expAccount = expAccountService.getExpAccount(loginInfo.getId());
        Account account = new Account();
        account.setUsableAmount(expAccount.getUsableAmount());
        account.setFreezedAmount(expAccount.getFreezedAmount());
        BidRequest bidRequest = bidingCheck(bidRequestId, amount, loginInfo, account);
        //设置借款对象
        //投标数增加
        bidRequest.addBidCount();
        //当前投资总额要增加
        bidRequest.addCurrentSum(amount);
        //设置投标对象
        //投标金额
        bidService.save(bidRequest, amount);
        //投资人的可用余额要减少,冻结资金要增加
        expAccount.subtractUsableAmount(amount);
        expAccount.addFreezedAmount(amount);
        expAccountService.update(expAccount);
        //设置流水
        //增加一条流水记录
        expAccountFlowService.createFreezedSuccessFlow(bidRequest.getTitle(), expAccount, amount);
        //如果是最后一笔投标,则自动进入满标二审
        if (bidRequest.getCurrentSum().compareTo(bidRequest.getBidRequestAmount()) == 0) {
            //将借款对象的状态设置为满标二审
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_APPROVE_PENDING_2);
            //投标对象的状态也随之改变,变为满标二审
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_APPROVE_PENDING_2);
        }
        update(bidRequest);

    }


    private BidRequest bidingCheck(Long bidRequestId, BigDecimal amount, LoginInfo loginInfo, Account account) {
        AssertUtil.instance().isFalse(account.getUsableAmount().compareTo(amount) < 0, ErrorCode.INSUFFICIENT_BALANCE_AVAILABLE_FOR_ACCOUNT);
        //总的投资金额是否小于等于借款金额的50%
        BigDecimal totalBidAmount = bidService.getTotalBidAmountByBidUserIdAndBidRequestId(bidRequestId, loginInfo.getId(), Constant.BIDREQUEST_STATE_BIDDING);
        BigDecimal temp = totalBidAmount.add(amount);
        BidRequest bidRequest = getBidRequestById(bidRequestId);
        BigDecimal bidRequestAmount = bidRequest.getBidRequestAmount().multiply(new BigDecimal("0.5"));
        AssertUtil.instance().isFalse(temp.compareTo(bidRequestAmount) > 0, ErrorCode.THE_TOTAL_INVESTMENT_AMOUNT_IS_GREATER_THAN_THE_MAXIMUM_INVESTMENT_AMOUNT)
                //投资金额是否小于等于还需金额
                .isFalse(bidRequest.getRemainAmount().compareTo(amount) < 0, ErrorCode.EXCEEDING_THE_REMAINING_INVESTMENT_AMOUNT);
        //还需金额大于等于最小投标金额
        if (bidRequest.getMinBidAmount().compareTo(bidRequest.getRemainAmount()) < 0) {
            //投标金额大于等于最小投标金额
            AssertUtil.instance().isFalse(bidRequest.getMinBidAmount().compareTo(amount) > 0, ErrorCode.THE_INVESTMENT_AMOUNT_IS_LESS_THAN_THE_MINIMUM_BID_AMOUNT);
        } else {
            //还需金额小于最小投标金额
            //只允许一次性投完
            AssertUtil.instance().isFalse(bidRequest.getRemainAmount().compareTo(amount) != 0, ErrorCode.MUST_FILL_THE_REMAINING_LOAN);
        }
        return bidRequest;
    }

    /**
     * @param id     借款对象的id
     * @param remark 风控备注
     * @param state  审核的结果
     */
    @Override
    public void bidRequestAudit1(Long id, String remark, Integer state) {
        //判断借款是否处在满标一审的状态
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(id);
        AssertUtil.instance().isFalse(bidRequest.getBidRequestState().intValue() != Constant.BIDREQUEST_STATE_APPROVE_PENDING_1, ErrorCode.HAVE_TO_REVIEW);
        //设置审核信息
        bidRequestAuditHistoryService.save(bidRequest, state, remark, Constant.APPROVE_PENDING_1);
        //如果审核通过
        if (state == AuditBaseDomain.AUTH_SUCCESS) {
            //将借款对象的状态设置为满标二审
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_APPROVE_PENDING_2);
            //将与之关联的投标对象的状态同步为满标二审状态
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_APPROVE_PENDING_2);

        } else {
            auditRefused(bidRequest);

            //更新
        }
        update(bidRequest);
    }

    private void auditRefused(BidRequest bidRequest) {
        //如果审核失败
        //去掉用户处在借款流程中的位状态
        UserInfo userInfo = userInfoService.getUserInfo(bidRequest.getCreateUser().getId());
        userInfo.removeBitState(BitStatesUtils.HAS_BIDREQUEST_IN_PROCESS);
        userInfoService.update(userInfo);
        //将借款对象的状态设置为审核拒绝
        bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_REJECTED);
        //将将与之关联的投标对象的状态同步为审核拒绝
        bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_REJECTED);
        //查询出不同投资人对该借款的投资金额
        //缓存查询到的账户,减少重复
        Map<Long, Account> accountMap = new HashMap<>();
        List<Bid> bids = bidRequest.getBids();
        for (int i = 0; i < bids.size(); i++) {
            //减少与该借款对象有关的投资人的冻结资金
            //增加与该借款对象有关的投资人的可用剩余资金
            Bid bid = bids.get(i);
            Long bidUserId = bid.getBidUser().getId();
            Account account = accountMap.get(bidUserId);
            if (account == null) {
                account = accountService.getAccount(bidUserId);
                accountMap.put(bidUserId, account);
            }
            account.addUsableAmount(bid.getAvailableAmount());
            account.subtractFreezedAmount(bid.getAvailableAmount());
            accountService.update(account);
            account.setVersion(account.getVersion() + 1);
            //保存ACCOUNT_ACTIONTYPE_BID_UNFREEZED类型的流水
            accountFlowService.createBidFailFlow(account, bid);
        }
    }

    /**
     * 满标2审
     *
     * @param id     借款对象的id
     * @param remark 风控备注
     * @param state  审核的结果
     */
    @Override
    public void bidRequestAudit2(Long id, String remark, Integer state) {
        //判断是否处在满标二审的状态
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(id);
        AssertUtil.instance().isFalse(bidRequest.getBidRequestState().intValue() == Constant.BIDREQUEST_STATE_PAYING_BACK, ErrorCode.HAVE_TO_REVIEW);
        //设置审核信息
        bidRequestAuditHistoryService.save(bidRequest, state, remark, Constant.APPROVE_PENDING_2);
        //如果审核成功
        if (state == AuditBaseDomain.AUTH_SUCCESS) {
            //对借款人而言
            Long borrowerUserId = bidRequest.getCreateUser().getId();
            //账户可用余额增加
            Account borrowerAccount = accountService.getAccount(borrowerUserId);
            borrowerAccount.addUsableAmount(bidRequest.getBidRequestAmount());
            //生成借款成功流水
            accountFlowService.createBorrowerSuccessFlow(borrowerAccount, bidRequest);
            //代还总额增加--在原有的基础上加
            BigDecimal totalBorrowerAmount = bidRequest.getBidRequestAmount().add(bidRequest.getTotalRewardAmount());
            borrowerAccount.setUnReturnAmount(borrowerAccount.getUnReturnAmount().add(totalBorrowerAmount));
            //授信额度减少--在原有的基础上减
            borrowerAccount.setRemainBorrowLimit(borrowerAccount.getRemainBorrowLimit().subtract(bidRequest.getBidRequestAmount()));
            //去掉userInfo中处于借款流程中的位状态
            UserInfo userInfo = userInfoService.getUserInfo(borrowerUserId);
            userInfo.removeBitState(BitStatesUtils.HAS_BIDREQUEST_IN_PROCESS);
            userInfoService.update(userInfo);
            //支付平台借款成功的管理费
            //平台管理费
            BigDecimal managementCharge = CalculatetUtil.calAccountManagementCharge(bidRequest.getBidRequestAmount());
            //可用余额减少
            borrowerAccount.subtractUsableAmount(managementCharge);
            accountService.update(borrowerAccount);
            //产生支付平台管理费流水
            accountFlowService.createPaymentManagementFlow(managementCharge, borrowerAccount, bidRequest.getTitle());


            //对投标人而言
            //todo
            Map<Long, Account> accountMap = new HashMap<>();
            List<Bid> bids = bidRequest.getBids();
            for (int i = 0; i < bids.size(); i++) {
                Bid bid = bids.get(i);
                //冻结资金减少
                Long bidUserId = bid.getBidUser().getId();
                Account bidUserAccount = accountMap.get(bidUserId);
                if (bidUserAccount == null) {
                    bidUserAccount = accountService.getAccount(bidUserId);
                    accountMap.put(bidUserId, bidUserAccount);
                }
                bidUserAccount.subtractFreezedAmount(bid.getAvailableAmount());
                //产生投标成功,冻结资金减少流水
                accountFlowService.createBorrowerSuccessFreezedFlow(bidUserAccount, bid.getAvailableAmount(), bid.getBidRequestTitle());
                //代收本金增加
               /* BigDecimal unReceivePrincipal = bidUserAccount.getUnReceivePrincipal().add(bid.getAvailableAmount());
                bidUserAccount.setUnReceivePrincipal(unReceivePrincipal);
                //代收利息增加
                BigDecimal unReceiveInterest =  bid.getAvailableAmount()
                        .divide(bidRequest.getBidRequestAmount(),Constant.CAL_SCALE, RoundingMode.HALF_UP)
                        .multiply(bidRequest.getTotalRewardAmount());
                bidUserAccount.setUnReceiveInterest(bidUserAccount.getUnReceiveInterest().add(unReceiveInterest.setScale(Constant.STORE_SCALE, RoundingMode.HALF_UP)));*/
            }
            //对借款对象
            //借款对象的状态变为还款中
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PAYING_BACK);
            //对投标对象
            //投标对象中的借款状态变为还款中
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_PAYING_BACK);
            //为借款人生成还款计划
            List<PaymentSchedule> paymentSchedules = paymentScheduleService.loanPlan(bidRequest);
            for (PaymentSchedule paymentSchedule : paymentSchedules) {
                for (PaymentScheduleDetail paymentScheduleDetail : paymentSchedule.getPaymentScheduleDetailLists()) {
                    Account account = accountMap.get(paymentScheduleDetail.getToLoginInfo().getId());
                    account.setUnReceiveInterest(account.getUnReceiveInterest().add(paymentScheduleDetail.getInterest()));
                    account.setUnReceivePrincipal(account.getUnReceivePrincipal().add(paymentScheduleDetail.getPrincipal()));
                }
            }
            for (Account account : accountMap.values()) {
                accountService.update(account);
            }

            //对平台而言
            //系统账户可用余额增加
            SystemAccount systemAccount = systemAccountService.getSystemAccount();
            systemAccount.setUsableAmount(systemAccount.getUsableAmount().add(managementCharge));
            //产生系统账户收到账户管理费（借款管理费）流水
            systemAccountFlowService.createReceiveManageChargeFlow(systemAccount, managementCharge, bidRequest.getTitle());
            systemAccountService.update(systemAccount);
        } else {
            //如果审核失败
            //同满标一审失败
            auditRefused(bidRequest);
        }
        update(bidRequest);
    }

    @Override
    public void expBidRequestAudit2(Long id, String remark, Integer state) {
        //判断是否处在满标二审的状态
        BidRequest bidRequest = bidRequestMapper.selectByPrimaryKey(id);
        AssertUtil.instance().isFalse(bidRequest.getBidRequestState().intValue() == Constant.BIDREQUEST_STATE_PAYING_BACK, ErrorCode.HAVE_TO_REVIEW);
        //设置审核信息
        bidRequestAuditHistoryService.save(bidRequest, state, remark, Constant.APPROVE_PENDING_2);
        Map<Long, ExpAccount> expAccountMap = new HashMap<>();
        //如果审核成功
        if (state == AuditBaseDomain.AUTH_SUCCESS) {
            //对投标人而言
            List<Bid> bids = bidRequest.getBids();
            for (int i = 0; i < bids.size(); i++) {
                Bid bid = bids.get(i);
                //冻结资金减少
                Long bidUserId = bid.getBidUser().getId();
                ExpAccount bidUserExpAccount = expAccountMap.get(bidUserId);
                if (bidUserExpAccount == null) {
                    bidUserExpAccount = expAccountService.getExpAccount(bidUserId);
                    expAccountMap.put(bidUserId, bidUserExpAccount);
                }
                bidUserExpAccount.subtractFreezedAmount(bid.getAvailableAmount());
                //产生投标成功,冻结资金减少流水
                expAccountFlowService.createBorrowerSuccessFreezedFlow(bidUserExpAccount, bid.getAvailableAmount(), bid.getBidRequestTitle());
            }
            //借款对象的状态变为还款中
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PAYING_BACK);
            //对投标对象
            //投标对象中的借款状态变为还款中
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_PAYING_BACK);
            //为借款人生成还款计划
            paymentScheduleService.loanPlan(bidRequest);
            for (ExpAccount expAccount : expAccountMap.values()) {
                expAccountService.update(expAccount);
            }
        } else {
            //如果审核失败
            //同满标一审失败
            //如果审核失败
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_REJECTED);
            //将将与之关联的投标对象的状态同步为审核拒绝
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_REJECTED);
            //查询出不同投资人对该借款的投资金额
            //缓存查询到的账户,减少重复
            List<Bid> bids = bidRequest.getBids();
            for (int i = 0; i < bids.size(); i++) {
                //减少与该借款对象有关的投资人的体验金冻结资金
                //增加与该借款对象有关的投资人的可用剩余体验资金
                Bid bid = bids.get(i);
                Long bidUserId = bid.getBidUser().getId();
                ExpAccount expAccount = expAccountMap.get(bidUserId);
                if (expAccount == null) {
                    expAccount = expAccountService.getExpAccount(bidUserId);
                    expAccountMap.put(bidUserId, expAccount);
                }
                expAccount.addUsableAmount(bid.getAvailableAmount());
                expAccount.subtractFreezedAmount(bid.getAvailableAmount());
                expAccountService.update(expAccount);
                expAccount.setVersion(expAccount.getVersion() + 1);
                //保存ACCOUNT_ACTIONTYPE_BID_UNFREEZED类型的流水
                expAccountFlowService.createBidFailFlow(expAccount, bid);
            }
        }
        update(bidRequest);
    }


    /**
     * 还款
     *
     * @param id 还款计划id
     */
    @Override
    public void returnMoney(Long id) {
        //判断当可用余额是否大于等于本期待还款总额
        Long userId = UserContext.getLoginInfo().getId();
        Account borrowUserAccount = accountService.getAccount(userId);
        PaymentSchedule paymentSchedule = paymentScheduleService.getPaymentSchedule(id);
        AssertUtil.instance()
                //判断该期的还款状态是否处在待还或逾期的状态
                .isFalse(paymentSchedule.getState().intValue() == Constant.PAYMENT_STATE_DONE, ErrorCode.THE_LOAN_HAS_BEEN_REPAID)
                //判断当前人是否为还款人
                .isFalse(paymentSchedule.getBorrowUser().getId().longValue() != userId.longValue(), ErrorCode.NOT_A_PAYER);
        //判断可用余额是否大于待还总额
        if (paymentSchedule.getState() == Constant.PAYMENT_STATE_OVERDUE) {
            AssertUtil.instance().isFalse(borrowUserAccount.getUsableAmount().compareTo(paymentSchedule.getTotalAmountAddLatePayment()) < 0, ErrorCode.INSUFFICIENT_BALANCE_AVAILABLE_FOR_ACCOUNT);
        } else {
            AssertUtil.instance().isFalse(borrowUserAccount.getUsableAmount().compareTo(paymentSchedule.getTotalAmount()) < 0, ErrorCode.INSUFFICIENT_BALANCE_AVAILABLE_FOR_ACCOUNT);
        }
        //设置还款日期
        Date payDate = new Date();

        //借款人
        BigDecimal totalAmount = paymentSchedule.getTotalAmount();
        //借款人的可用余额减少
        borrowUserAccount.subtractUsableAmount(totalAmount);
        //产生还款成功流水
        accountFlowService.createRepaymentSuccessFlow(borrowUserAccount, paymentSchedule.getBidRequestTitle(), totalAmount);
        //恢复借款人的授信额度,并且可申请提升信用额度
        borrowUserAccount.setRemainBorrowLimit(borrowUserAccount.getRemainBorrowLimit().add(paymentSchedule.getPrincipal()));
        //如果逾期还款,缴纳滞纳金
        BigDecimal latePaymentAmount = paymentSchedule.getLatePayment();
        if (paymentSchedule.getState() == Constant.PAYMENT_STATE_OVERDUE) {
            borrowUserAccount.subtractUsableAmount(latePaymentAmount);
            //产生支付投资人滞纳金流水
            accountFlowService.createPayLateFeeFlow(borrowUserAccount, latePaymentAmount, paymentSchedule.getBidRequestTitle(), paymentSchedule.getMonthIndex(), DateUtil.getTimeDistance(paymentSchedule.getDeadline(), payDate));
        }
        //待还总额减少
        borrowUserAccount.setUnReturnAmount(borrowUserAccount.getUnReturnAmount().subtract(totalAmount));
        //投资人
        //投资人的可用余额增加
        List<PaymentScheduleDetail> paymentScheduleDetailLists = paymentSchedule.getPaymentScheduleDetailLists();
        paymentSchedule.setPayDate(payDate);
        Map<Long, Account> bidUserAccountMap = new HashMap<>();
        BidRequest bidRequest = getBidRequestById(paymentSchedule.getBidRequestId());
        SystemAccount systemAccount = systemAccountService.getSystemAccount();
        for (int i = 0; i < paymentScheduleDetailLists.size(); i++) {
            PaymentScheduleDetail paymentScheduleDetail = paymentScheduleDetailLists.get(i);
            paymentScheduleDetail.setPayDate(payDate);
            paymentScheduleDetailService.upadtePayDate(paymentScheduleDetail);
            Long bidUserId = paymentScheduleDetail.getToLoginInfo().getId();
            Account bidUserAccount = bidUserAccountMap.get(bidUserId);
            if (bidUserAccount == null) {
                bidUserAccount = accountService.getAccount(bidUserId);
                bidUserAccountMap.put(bidUserId, bidUserAccount);
            }
            BigDecimal receiptAccount = paymentScheduleDetail.getTotalAmount();
            bidUserAccount.addUsableAmount(paymentScheduleDetail.getTotalAmount());
            //产生收款成功流水
            accountFlowService.createBiddingReturnFlow(bidUserAccount, paymentSchedule.getBidRequestTitle(), receiptAccount);
            //支付利息管理费
            //利息管理费
            BigDecimal interestManagerCharge = CalculatetUtil.calInterestManagerCharge(paymentScheduleDetail.getInterest());
            bidUserAccount.subtractUsableAmount(interestManagerCharge);
            //产生利息管理费流水
            String bidRequestTitle = paymentSchedule.getBidRequestTitle();
            accountFlowService.createInterestManagerChargeFlow(bidUserAccount, bidRequestTitle, interestManagerCharge);
            //收取滞纳金
            if (paymentSchedule.getState() == Constant.PAYMENT_STATE_OVERDUE) {
                Bid bid = bidService.getBid(paymentScheduleDetail.getBidId());
                BigDecimal receiveLatePaymentAmount = CalculatetUtil.calReceiveLatePaymentAmount(bid.getAvailableAmount(), bidRequest.getBidRequestAmount(), latePaymentAmount);
                bidUserAccount.addUsableAmount(receiveLatePaymentAmount);
                //产生收取滞纳金流水
                accountFlowService.createReceiveLatePaymentAmountFlow(bidUserAccount, receiveLatePaymentAmount, paymentSchedule.getBidRequestTitle(), paymentSchedule.getMonthIndex(), DateUtil.getTimeDistance(paymentSchedule.getDeadline(), payDate));
            }
            //平台
            //系统收取利息管理费,产生receiveInterestManagerChargeFlow
            systemAccount.setUsableAmount(systemAccount.getUsableAmount().add(interestManagerCharge));
            systemAccountFlowService.createReceiveInterestManagerChargeFlow(systemAccount, interestManagerCharge, bidRequestTitle, paymentSchedule.getMonthIndex());
            //待收本金减少
            bidUserAccount.setUnReceivePrincipal(bidUserAccount.getUnReceivePrincipal().subtract(paymentScheduleDetail.getPrincipal()));
            //待收利息减少
            bidUserAccount.setUnReceiveInterest(bidUserAccount.getUnReceiveInterest().subtract(paymentScheduleDetail.getInterest()));
            accountService.update(bidUserAccount);
            bidUserAccount.setVersion(bidUserAccount.getVersion() + 1);

            //将招标中的债权的状态设置为撤销
            Long bidId = paymentScheduleDetail.getBidId();
            CreditTransfer creditTransfer = creditTransferService.getCreditTransferByBidIdAndState(bidId, Constant.BIDREQUEST_STATE_BIDDING);
            if (creditTransfer != null) {
                creditTransfer.setBidRequestState(Constant.BIDREQUEST_STATE_UNDO);
                creditTransferService.update(creditTransfer);
                paymentScheduleDetailService.updateTransferStateByBidIdAndUserId(bidId, creditTransfer.getTransFrom().getId(), false);
            }
            //将与该债权有关的收款计划的转让状态设置为正常


        }
        systemAccountService.update(systemAccount);
        //还款计划对象
        //逾期
        if (paymentSchedule.getState() == Constant.PAYMENT_STATE_OVERDUE) {
            //将借款对象的状态设置为还款中
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PAYING_BACK);
            //将投标对象的状态设置为还款中
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_PAYING_BACK);
        }
        paymentSchedule.setState(Constant.PAYMENT_STATE_DONE);
        paymentScheduleService.update(paymentSchedule);
        int count = paymentScheduleService.listPaymentScheduleStatesByBidRequestId(paymentSchedule.getBidRequestId(), Constant.PAYMENT_STATE_DONE);
        //判断每期的还款状态是否都为已还
        if (count == bidRequest.getMonthes2Return()) {
            //将借款对象的状态设置为已还清
            //将投标对象的状态设置为已还清
            bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_COMPLETE_PAY_BACK);
            bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_COMPLETE_PAY_BACK);
        }
        accountService.update(borrowUserAccount);
        update(bidRequest);
    }


    //2.服务器启动时查询一次数据库
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        log.debug("系统启动是查询待发标");
        listBidRequests();
    }

    @Override
    public void overdue() {
        List<PaymentSchedule> paymentSchedulelists = paymentScheduleService.listPaymentScheduleByState(Constant.PAYMENT_STATE_NORMAL);
        Date date = new Date();
        for (int i = 0; i < paymentSchedulelists.size(); i++) {
            PaymentSchedule paymentSchedule = paymentSchedulelists.get(i);
            Date deadline = paymentSchedule.getDeadline();
            //如果是信用标...,
            if (paymentSchedule.getDeadline().before(date)) {
                if (paymentSchedule.getBidRequestType() == 0) {
                    log.debug("逾期了");
                    //借款对象的状态设置为逾期
                    BidRequest bidRequest = getBidRequestById(paymentSchedule.getBidRequestId());
                    //将借款对象的状态设置为逾期
                    bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_PAY_BACK_OVERDUE);
                    //将投标对象的状态设置为逾期
                    bidService.updateByBidRequestIdAndState(bidRequest.getId(), Constant.BIDREQUEST_STATE_PAY_BACK_OVERDUE);
                    update(bidRequest);
                    //设置还款计划对象的状态为逾期
                    paymentSchedule.setState(Constant.PAYMENT_STATE_OVERDUE);
                    paymentScheduleService.updateLatePayment(paymentSchedule);
                } else if (paymentSchedule.getBidRequestType() == 2) {
                    //如果是体验标...
                    expRepayment(paymentSchedule);
                }
            }
        }
    }

    @Override
    public void latePayment() {
        List<PaymentSchedule> paymentSchedulelists = paymentScheduleService.listPaymentScheduleByState(Constant.PAYMENT_STATE_OVERDUE);
        for (PaymentSchedule paymentSchedule : paymentSchedulelists) {
            //保存逾期记录
            //产生日复利千分之八的滞纳金
            //滞纳金
            BigDecimal totalLatePayment = CalculatetUtil.calLatePaymentAmount(paymentSchedule.getTotalAmount(), paymentSchedule.getLatePayment());
            if (totalLatePayment.compareTo(paymentSchedule.getTotalAmount()) <= 0) {
                paymentSchedule.setLatePayment(paymentSchedule.getLatePayment().add(totalLatePayment));
            } else {
                paymentSchedule.setLatePayment(paymentSchedule.getTotalAmount());
            }

        }

    }

    /**
     * 体验标发标
     *
     * @param bidRequest
     */
    @Override
    public void expBidRequestPublish(BidRequest bidRequest) {
        //借款金额是否大于等于系统最低借款
        AssertUtil.instance()
                .isFalse(bidRequest.getBidRequestAmount().compareTo(Constant.SMALLEST_BIDREQUEST_AMOUNT) < 0, ErrorCode.LESS_THAN_THE_MINIMUM_LOAN)
                //借款利率是否大于等于系统最低利率,小于等于系统最高利率
                .isFalse(bidRequest.getCurrentRate().compareTo(Constant.SMALLEST_CURRENT_RATE) < 0, ErrorCode.LESS_THAN_THE_SYSTEM_MINIMUM_INTEREST_RATE)
                .isFalse(bidRequest.getCurrentRate().compareTo(Constant.MAX_CURRENT_RATE) > 0, ErrorCode.GREATER_THAN_THE_SYSTEM_MINIMUM_INTEREST_RATE);
        //还款的期限
        AssertUtil.instance()
                .isFalse(bidRequest.getMonthes2Return().compareTo(Constant.EXP_REPAYMENT_MONTH) != 0, ErrorCode.INVALID_EXPERIENCE_ISSUE_NUMBER_OF_MONTHS);
        //是否大于最小投标金额
        AssertUtil.instance()
                .isFalse(bidRequest.getMinBidAmount().compareTo(Constant.SMALLEST_BID_AMOUNT) < 0, ErrorCode.LESS_THAN_THE_MINIMUM_BID_AMOUNT_OF_THE_SYSTEM);
        //是否在系统规定的招标天数
        AssertUtil.instance()
                .isFalse(bidRequest.getDisableDays() < Constant.MINIMUM_TENDER_DAYS, ErrorCode.LESS_THAN_THE_MAXIMUM_NUMBER_OF_BIDDING_DAYS);
        AssertUtil.instance()
                .isFalse(bidRequest.getDisableDays() > Constant.MAXIMUM_NUMBER_OF_BIDDING_DAYS, ErrorCode.GREATER_THAN_THE_MAXIMUM_NUMBER_OF_BIDDING_DAYS);
        AssertUtil.instance().isNotNull(bidRequest.getTitle(), ErrorCode.BORROWING_TITLE_IS_EMPTY);
        //保存信用标对象
        BidRequest temp = new BidRequest();
        temp.setBidRequestType(Constant.EXPERIENCE_BIDREQUEST_TYPE_CREDITTRANSFER);
        insert(bidRequest, UserContext.getLoginInfo(), temp);
    }

    @Override
    public void expRepayment(PaymentSchedule paymentSchedule) {
        //平台支付体验金利息
        BigDecimal interest = paymentSchedule.getInterest();
        String bidRequestTitle = paymentSchedule.getBidRequestTitle();

        SystemAccount systemAccount = systemAccountService.getSystemAccount();
        systemAccount.subtractFreezedAmount(interest);
        //产生支付体验金利息
        systemAccountFlowService.createPaymentExperienceInterest(systemAccount, interest, bidRequestTitle);

        //投资人
        List<PaymentScheduleDetail> paymentScheduleDetailLists = paymentSchedule.getPaymentScheduleDetailLists();
        Map<Long, ExpAccount> expAccountMap = new HashMap<>();
        Map<Long, Account> accountMap = new HashMap<>();
        BidRequest bidRequest = getBidRequestById(paymentSchedule.getBidRequestId());
        Date date = new Date();
        //设置收款日期
        paymentSchedule.setPayDate(date);
        for (PaymentScheduleDetail paymentScheduleDetail : paymentScheduleDetailLists) {
            //设置还款日期
            paymentScheduleDetail.setPayDate(date);
            Bid bid = bidService.getBid(paymentScheduleDetail.getBidId());
            Long toLoginInfoId = paymentScheduleDetail.getToLoginInfo().getId();
            paymentScheduleDetailService.upadtePayDate(paymentScheduleDetail);
            ExpAccount expAccount = expAccountMap.get(toLoginInfoId);
            if (expAccount == null) {
                expAccount = expAccountService.getExpAccount(toLoginInfoId);
                expAccountMap.put(toLoginInfoId, expAccount);
            }
            Account bidUserAccount = accountMap.get(toLoginInfoId);
            if (bidUserAccount == null) {
                bidUserAccount = accountService.getAccount(toLoginInfoId);
                accountMap.put(toLoginInfoId, bidUserAccount);
            }
            //投资人的体验金账户变化
            //退回体验金本金
            expAccount.addUsableAmount(bid.getAvailableAmount());
            expAccountFlowService.createReturnExperienceGoldPrincipal(expAccount, bid.getAvailableAmount(), bidRequestTitle);
            //先减去垫付的部分,如果用户的体验金因在投标中,无法回收指定金额的体验金,则产生垫收,在退回本金之后要将该金额
            BigDecimal unReturnExpAmount = expAccount.getUnReturnExpAmount();
            expAccount.subtractUsableAmount(unReturnExpAmount);
            expAccount.setUnReturnExpAmount(expAccount.getUnReturnExpAmount().subtract(unReturnExpAmount));
            //投资人账户可用余额增加
            BigDecimal bidInterest =  CalculatetUtil.calMonthlyReceiveInterest(bid.getAvailableAmount(),bidRequest.getBidRequestAmount(),interest);
            bidUserAccount.addUsableAmount(bidInterest);
            //创建收取体验金利息流水
            accountFlowService.creatReceivePaymentExperienceInterest(bidUserAccount, bidInterest, bidRequestTitle);
            BigDecimal expInterestMgrAmount = CalculatetUtil.calInterestManagerCharge(bidInterest);
            accountFlowService.createInterestManagerChargeFlow(bidUserAccount,bidRequestTitle,expInterestMgrAmount);
            //平台
            //支付平台利息管理费
            systemAccount.addUsableAmount(expInterestMgrAmount);
            //产生收取利息管理费流水
            systemAccountFlowService.createReceiveExperienceInterestManagerChargeFlow(systemAccount, expInterestMgrAmount, bidRequestTitle);
            bidService.updateByBidRequestIdAndState(bidRequest.getId(),Constant.BIDREQUEST_STATE_COMPLETE_PAY_BACK);
        }
        for (ExpAccount expAccount : expAccountMap.values()) {
            expAccountService.update(expAccount);
        }
        for (Account account : accountMap.values()) {
            accountService.update(account);
        }
        paymentSchedule.setState(Constant.PAYMENT_STATE_DONE);
        paymentScheduleService.update(paymentSchedule);
        systemAccountService.update(systemAccount);
        //借款对象的状态设置为已还清
        bidRequest.setBidRequestState(Constant.BIDREQUEST_STATE_COMPLETE_PAY_BACK);
        update(bidRequest);
    }


    @Override
    public void recyclingExperience() {
        Date date = new Date();
        List<ExpAccountGrantRecord> expAccountGrantRecords = expAccountGrantRecordService.listGrantRecordByState(ExpAccountGrantRecord.STATE_NORMAL);
        for (ExpAccountGrantRecord expAccountGrantRecord : expAccountGrantRecords) {
            Date returnDate = expAccountGrantRecord.getReturnDate();
            if (returnDate.before(date)) {
                Long grantUserId = expAccountGrantRecord.getGrantUserId();
                ExpAccount expAccount = expAccountService.getExpAccount(grantUserId);
                BigDecimal amount = expAccountGrantRecord.getAmount();
                BigDecimal usableAmount = expAccount.getUsableAmount();
                if (amount.compareTo(usableAmount) <= 0) {
                    expAccount.subtractUsableAmount(amount);
                } else {
                    BigDecimal unReturnExpAmount = usableAmount.subtract(amount).abs();
                    expAccount.setUnReturnExpAmount(expAccount.getUnReturnExpAmount().add(unReturnExpAmount));
                    expAccount.setUsableAmount(Constant.ZERO);
                }
                //回收体验金,体验金余额减少
                expAccountService.update(expAccount);
                String note = "回收id为" + grantUserId + "用户体验金[" + amount + "]元";
                expAccountFlowService.createRecyclingExperienceFlow(expAccount, amount, note, Constant.INITIAL_EXPERIENCE);
                expAccountGrantRecord.setState(ExpAccountGrantRecord.STATE_RETURN);
                expAccountGrantRecordService.update(expAccountGrantRecord);
            }
        }
    }

}
